package api

import (
	"fmt"
	"net/url"
	"strings"

	jsoniter "github.com/json-iterator/go"
	"github.com/pkg6/go-requests"
)

type ApiResp interface {
	IsOk() bool
	Err() error
}

func Get(url string, params any, output any) error {
	resp, err := requests.Get(url, params, func(client *requests.Client) {
		client.SetJSONMarshaler(jsoniter.Marshal).SetJSONUnmarshaler(jsoniter.Unmarshal).
			WithUserAgent("Mozilla/5.0 (platform; rv:geckoversion) Gecko/geckotrail Firefox/firefoxversion")
	})
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.IsError() {
		return fmt.Errorf("http status: %v", resp.Status)
	}
	if apiResp, ok := output.(ApiResp); ok && !apiResp.IsOk() {
		return apiResp.Err()
	}
	return resp.Unmarshal(output)
}

func PostJson(uri string, queryParams map[string]string, body any, output any) error {
	realUrl := uri
	if queryParams != nil || len(queryParams) > 0 {
		var a []string
		for k, v := range queryParams {
			a = append(a, fmt.Sprintf("%s=%s", k, url.QueryEscape(v)))
		}
		realUrl += "?" + strings.Join(a, "&")
	}
	resp, err := requests.PostJson(realUrl, body, func(client *requests.Client) {
		client.SetJSONMarshaler(jsoniter.Marshal).SetJSONUnmarshaler(jsoniter.Unmarshal).
			WithUserAgent("Mozilla/5.0 (platform; rv:geckoversion) Gecko/geckotrail Firefox/firefoxversion")
	})
	return afterResp(resp, err, output)
}

func afterResp(resp *requests.Response, err error, output any) error {
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.IsError() {
		return fmt.Errorf("http status: %v", resp.Status)
	}
	if apiResp, ok := output.(ApiResp); ok && !apiResp.IsOk() {
		return apiResp.Err()
	}
	return resp.Unmarshal(output)
}

func PostForm(uri string, queryParams map[string]string, output any) error {
	data := url.Values{}
	if queryParams != nil || len(queryParams) > 0 {
		for k, v := range queryParams {
			data.Add(k, v)
		}
	}
	resp, err := requests.PostForm(uri, data, func(client *requests.Client) {
		client.SetJSONUnmarshaler(jsoniter.Unmarshal)
	})
	return afterResp(resp, err, output)
}
